import pandas as pd
import numpy as np
import statsmodels.api as sm
import datetime
import matplotlib.pyplot as plt
from sklearn.covariance import LedoitWolf
from IPython.display import display, HTML
import warnings
warnings.filterwarnings('ignore')
# Pull the list of utility stock tickers from wikepedia
# store them in utlilities tickers
import requests
url = "https://en.wikipedia.org/wiki/List_of_S%26P_500_companies"
response = requests.get(url)
text = response.text
from bs4 import BeautifulSoup
soup = BeautifulSoup(text)
tag_list = soup.find_all("tr")
utilities_tickers = list()
for tag in tag_list:
try:
if tag.find_all('td')[2].get_text() == 'Utilities':
utilities_tickers.append(tag.find_all('td')[0].get_text().replace("\n", ""))
except IndexError:
pass
import datetime as dt
from pandas_datareader import data as pdr
import yfinance as yfin
yfin.pdr_override()
start_date = dt.datetime(1960, 1, 1)
end_date = dt.datetime(2023, 1, 1)
utilities_stock_data = dict()
for ticker in utilities_tickers:
df = pdr.get_data_yahoo(ticker, start=start_date, end=end_date)
df = df.reset_index()
df['Date'] = pd.to_datetime(df['Date'])
utilities_stock_data[ticker] = df
[*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed [*********************100%***********************] 1 of 1 completed
monthly_spy_data = pd.read_csv('./SPY.csv', index_col='Date', parse_dates=True)
monthly_spy_data['Monthly_Return'] = monthly_spy_data['Adj Close'].pct_change(periods=1)
monthly_spy_data.index = monthly_spy_data.index - pd.DateOffset(days=1)
monthly_spy_data = monthly_spy_data.drop(monthly_spy_data.tail(5).index)
monthly_spy_data
| Open | High | Low | Close | Adj Close | Volume | Monthly_Return | |
|---|---|---|---|---|---|---|---|
| Date | |||||||
| 1993-01-31 | 43.968750 | 45.125000 | 42.812500 | 44.406250 | 25.390364 | 5417600 | NaN |
| 1993-02-28 | 44.562500 | 45.843750 | 44.218750 | 45.187500 | 25.837070 | 3019200 | 0.017594 |
| 1993-03-31 | 45.250000 | 45.250000 | 43.281250 | 44.031250 | 25.294857 | 2697200 | -0.020986 |
| 1993-04-30 | 44.093750 | 45.656250 | 43.843750 | 45.218750 | 25.977036 | 1808000 | 0.026969 |
| 1993-05-31 | 45.375000 | 45.812500 | 44.218750 | 45.062500 | 25.887280 | 3438000 | -0.003455 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 2022-08-31 | 392.890015 | 411.730011 | 357.040009 | 357.179993 | 352.746490 | 1998908600 | -0.096159 |
| 2022-09-30 | 361.079987 | 389.519989 | 348.109985 | 386.209991 | 382.982941 | 2024732000 | 0.085717 |
| 2022-10-31 | 390.140015 | 407.679993 | 368.790009 | 407.679993 | 404.273560 | 1745985300 | 0.055592 |
| 2022-11-30 | 408.769989 | 410.489990 | 374.769989 | 382.429993 | 379.234528 | 1735973600 | -0.061936 |
| 2022-12-31 | 384.369995 | 408.160004 | 377.829987 | 406.480011 | 404.934570 | 1575450100 | 0.067768 |
360 rows × 7 columns
# utilities data
for ticker in utilities_stock_data:
utilities_stock_data[ticker]= utilities_stock_data[ticker].set_index('Date')
utilities_stock_data[ticker] = utilities_stock_data[ticker].resample('M').last()
utilities_stock_data[ticker]['pct change'] = utilities_stock_data[ticker]['Adj Close'].pct_change()
pop = ['AES', 'AEE', 'CEG', 'AWK', 'CMS', 'FE', 'NRG', 'SRE'] # cutoff around ~400 months of data
for p in pop:
utilities_stock_data.pop(p)
# store data in dataframe
data = {}
for ticker in utilities_stock_data:
data[ticker] = utilities_stock_data[ticker]['pct change']
utilities_returns = pd.DataFrame(data)
utilities_returns = utilities_returns.set_index(utilities_stock_data['AEP'].index)
utilities_returns = utilities_returns.iloc[1: , :]
utilities_returns = utilities_returns.dropna()
utilities_returns
| LNT | AEP | ATO | CNP | ED | D | DTE | DUK | EIX | ETR | ... | EXC | NEE | NI | PCG | PNW | PPL | PEG | SO | WEC | XEL | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | |||||||||||||||||||||
| 1984-01-31 | 0.000000 | 0.072993 | 0.000000 | 0.032257 | 0.010101 | 0.067797 | 0.018182 | -0.009950 | -0.025157 | 0.009345 | ... | 0.043477 | -0.009317 | -0.034188 | 0.008403 | -0.006452 | 0.042425 | 0.027473 | -0.003139 | 0.004546 | -0.026315 |
| 1984-02-29 | -0.035087 | -0.052498 | 0.022555 | -0.028244 | -0.070189 | -0.095238 | 0.000000 | -0.068241 | -0.054839 | 0.037037 | ... | -0.012877 | -0.065570 | -0.008850 | -0.075000 | -0.019480 | 0.005813 | -0.083845 | -0.055118 | -0.072398 | -0.027028 |
| 1984-03-31 | -0.059091 | -0.029630 | 0.029412 | 0.019867 | 0.054945 | 0.011696 | -0.051107 | 0.060773 | -0.004815 | -0.032157 | ... | 0.008771 | 0.020619 | -0.017857 | -0.043466 | -0.046358 | -0.057803 | -0.012048 | 0.025000 | 0.014634 | -0.031250 |
| 1984-04-30 | 0.019324 | 0.007633 | -0.057142 | 0.025974 | 0.031250 | 0.080925 | -0.058253 | -0.015625 | 0.056338 | -0.057143 | ... | -0.104348 | 0.026936 | 0.000000 | 0.029126 | -0.104167 | 0.018405 | 0.085366 | 0.008129 | 0.028846 | 0.025090 |
| 1984-05-31 | 0.004739 | -0.019454 | 0.000000 | -0.026792 | 0.016500 | -0.069519 | 0.041237 | -0.002048 | -0.033333 | 0.020203 | ... | -0.008135 | -0.034739 | -0.063636 | 0.018868 | 0.062016 | 0.054217 | -0.028090 | -0.036544 | 0.009345 | 0.024475 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2022-08-31 | 0.001805 | 0.024625 | -0.060576 | 0.000436 | -0.007595 | -0.002196 | 0.000307 | -0.018510 | 0.000000 | 0.009997 | ... | -0.048458 | 0.011629 | -0.029276 | 0.135359 | 0.025589 | 0.000000 | -0.019948 | 0.011168 | 0.000471 | 0.014621 |
| 2022-09-30 | -0.131881 | -0.137225 | -0.101693 | -0.106248 | -0.122570 | -0.148178 | -0.111286 | -0.129922 | -0.155475 | -0.127233 | ... | -0.146891 | -0.078180 | -0.146391 | 0.013788 | -0.143862 | -0.121587 | -0.119246 | -0.117685 | -0.132926 | -0.132408 |
| 2022-10-31 | -0.007126 | 0.017004 | 0.046146 | 0.015259 | 0.025653 | 0.012444 | -0.025554 | 0.001720 | 0.061152 | 0.064693 | ... | 0.030166 | -0.011606 | 0.029384 | 0.194400 | 0.055218 | 0.044970 | -0.002845 | -0.037059 | 0.021246 | 0.017344 |
| 2022-11-30 | 0.079164 | 0.111336 | 0.135193 | 0.094143 | 0.124543 | -0.126626 | 0.034787 | 0.083559 | 0.110260 | 0.096165 | ... | 0.081385 | 0.098454 | 0.087583 | 0.051574 | 0.165303 | 0.114383 | 0.079900 | 0.043922 | 0.094332 | 0.078482 |
| 2022-12-31 | -0.019361 | -0.019112 | -0.067637 | -0.036001 | -0.027846 | 0.014526 | 0.021274 | 0.030621 | -0.034648 | -0.032425 | ... | 0.044960 | -0.012987 | -0.018611 | 0.035669 | -0.029111 | -0.002417 | 0.021088 | 0.055736 | -0.054267 | 0.005288 |
468 rows × 22 columns
Original attempt was to create custom market factors for within the S&P universe. After extensive searching it was found impossible to collect the data required without paying for a service. Therefore an alternative method of evaluating the factor model was required.
Exploring the difference between Fama French factors vs Asness and Frazzini factors as explained in Asness, C.S, and Frazzini, A. (2013), The Devil in HML’s Details.
Information on paper can be found: https://www.aqr.com/Insights/Research/Journal-Article/The-Devil-in-HMLs-Details
Paper can be found: https://www.iijournalseprint.com/JPM/AQR/Sum13DevilinHMLsDetails05t/index.html
Data can be found: https://www.aqr.com/Insights/Datasets/The-Devil-in-HMLs-Details-Factors-Monthly
The Journal of Portfolio Management, Vol. 39, No. 4, pp. 49-68
factor_df = pd.read_csv('./factor_FF_devil.csv', index_col=0)
factor_df.index = pd.to_datetime(factor_df.index, format='%Y%m') + datetime.timedelta(days=-1)
factor_df['HML devil'] = factor_df['HML devil']*100
factor_df = factor_df/100
factor_df
| MKT | SMB | HML FF | HML devil | RMW | CMA | RF | MOM | STR | |
|---|---|---|---|---|---|---|---|---|---|
| Date | |||||||||
| 1963-06-30 | -0.0039 | -0.0041 | -0.0097 | -0.0059 | 0.0068 | -0.0118 | 0.0027 | 0.0090 | -0.0008 |
| 1963-07-31 | 0.0507 | -0.0080 | 0.0180 | 0.0028 | 0.0036 | -0.0035 | 0.0025 | 0.0101 | 0.0130 |
| 1963-08-31 | -0.0157 | -0.0052 | 0.0013 | 0.0027 | -0.0071 | 0.0029 | 0.0027 | 0.0019 | 0.0119 |
| 1963-09-30 | 0.0253 | -0.0139 | -0.0010 | -0.0211 | 0.0280 | -0.0201 | 0.0029 | 0.0312 | -0.0066 |
| 1963-10-31 | -0.0085 | -0.0088 | 0.0175 | 0.0091 | -0.0051 | 0.0224 | 0.0027 | -0.0074 | 0.0112 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2022-08-31 | -0.0935 | -0.0097 | 0.0006 | -0.0274 | -0.0151 | -0.0084 | 0.0019 | 0.0347 | -0.0161 |
| 2022-09-30 | 0.0783 | 0.0186 | 0.0805 | 0.0502 | 0.0307 | 0.0652 | 0.0023 | 0.0387 | 0.0033 |
| 2022-10-31 | 0.0460 | -0.0267 | 0.0138 | 0.0241 | 0.0601 | 0.0311 | 0.0029 | -0.0201 | 0.0055 |
| 2022-11-30 | -0.0641 | -0.0016 | 0.0132 | -0.0044 | 0.0009 | 0.0419 | 0.0033 | 0.0452 | -0.0342 |
| 2022-12-31 | 0.0665 | 0.0443 | -0.0405 | 0.0476 | -0.0262 | -0.0453 | 0.0035 | -0.1598 | 0.0937 |
715 rows × 9 columns
def sampleMeanVariant(sigmahat, muhat, rf, kappa):
e = np.ones((sigmahat.shape[0], 1))
H = (muhat - rf*e).T @ np.linalg.inv(sigmahat) @ (muhat - rf*e)
aStar = (kappa-rf)/H * np.linalg.inv(sigmahat) @ (muhat - rf*e)
return aStar
sampleMeanVariant(np.cov(utilities_returns, rowvar=False), np.array([np.mean(utilities_returns, axis=0)]).T, factor_df['RF'][-1], 0.012)
array([[ 0.01174723],
[-0.16453512],
[ 0.24406775],
[-0.02551994],
[-0.13859163],
[ 0.08812135],
[ 0.19309851],
[-0.01928269],
[ 0.04250492],
[-0.12286952],
[-0.22672308],
[-0.01627721],
[ 0.00435655],
[ 0.44437863],
[-0.0012304 ],
[-0.00887804],
[-0.05948933],
[-0.04751013],
[ 0.01659133],
[ 0.43326368],
[ 0.21510329],
[ 0.00996532]])
def factorModel(returns, factorDF, rf, kappa, numFactors):
"""
returns - monthly returns dataframe of each equity (m,d)
factorDF - df of excess market returns, SMB, HML
rf - series of rf rate
kappa - targeted expected return for portfolio
numFactors - the number of factors in the model
"""
d = returns.shape[1]
# Compute the excess returns of each asset
excess_returns = returns.sub(rf,axis=0).values
# Define arrays to store the beta coefficients and residual variances
betas = np.zeros((d, numFactors))
residual_variances = np.zeros((d))
# Perform the OLS regression for each asset
for i in range(d):
# Extract the excess returns of the i-th asset
excess_asset_returns = excess_returns[:,i]
# Define the OLS model with the R-rf ~ MF-rf + SMB + HML
model = sm.OLS(excess_asset_returns,
sm.add_constant(factorDF))
# Fit the model and extract the regression coefficients and residuals
results = model.fit()
beta = results.params[1:]
residuals = results.resid
# Store the beta coefficients and residual variance for the i-th asset
betas[i] = beta
residual_variances[i] = np.var(residuals, ddof=numFactors + 1)
sigmaFactor = np.cov(factorDF.T)
Dhat = np.diag(residual_variances)
sigmahat = betas@sigmaFactor@betas.T + Dhat
muhat = returns.mean().values.reshape((-1, 1))
# pass most recent rf
return sampleMeanVariant(sigmahat, muhat, rf[-1], kappa)
AF_factorDF = factor_df[['MKT', 'SMB', 'HML devil']].loc['1/31/1984':'12/31/2022']
rf_DF = factor_df['RF'].loc['1/31/1984':'12/31/2022']
AF_a = factorModel(utilities_returns, AF_factorDF, rf_DF, kappa=.012,numFactors=3)
AF_a
array([[0.05654647],
[0.05334952],
[0.06741343],
[0.0371012 ],
[0.07089734],
[0.06932758],
[0.08302917],
[0.05912089],
[0.03889345],
[0.04043529],
[0.03750989],
[0.05049437],
[0.04955986],
[0.08639314],
[0.0401979 ],
[0.01763947],
[0.01730354],
[0.04307185],
[0.0556642 ],
[0.08926318],
[0.09038271],
[0.04852111]])
FF_factorDF = factor_df[['MKT', 'SMB', 'HML FF']].loc['1/31/1984':'12/31/2022']
FF_a = factorModel(utilities_returns, FF_factorDF, rf_DF, kappa=.012, numFactors=3)
FF_a
array([[0.05600936],
[0.05145666],
[0.06533542],
[0.03636784],
[0.07341181],
[0.06781274],
[0.08185201],
[0.05743151],
[0.03332141],
[0.03908481],
[0.04074068],
[0.04976133],
[0.04944596],
[0.08998026],
[0.04390553],
[0.01530909],
[0.01856316],
[0.04291205],
[0.05801989],
[0.0884523 ],
[0.0907776 ],
[0.05109328]])
def stein_wolf(returns, rf, params):
kappa = params[0]
mu_hat = np.mean(returns, axis=0)
sigma_hat = np.cov(returns, rowvar=False)
e = np.ones(len(mu_hat))
d = len(returns.columns)
N = len(returns)
mu_0 = ((mu_hat.T @ np.linalg.inv(sigma_hat) @ e)/(e.T @ np.linalg.inv(sigma_hat) @ e)) * e
alpha = (d + 2) / (d + 2 + (N - d - 2) * ((mu_hat - mu_0).T @ np.linalg.inv(sigma_hat) @ (mu_hat - mu_0)))
shrunk_mean = (alpha * mu_0) + ((1 - alpha) * mu_hat)
cov = LedoitWolf().fit(returns)
shrunk_var = cov.covariance_
return sampleMeanVariant(shrunk_var, np.array([shrunk_mean]).T, rf[-1], kappa)
stein_wolf(utilities_returns, rf_DF, [0.012])
array([[ 0.10207668],
[-0.14515308],
[ 0.24536392],
[-0.07190104],
[ 0.0497614 ],
[ 0.1951668 ],
[ 0.14421587],
[ 0.00491196],
[ 0.04215468],
[-0.11209936],
[-0.02282054],
[ 0.07205937],
[ 0.01451278],
[ 0.19992312],
[ 0.03772774],
[ 0.03048986],
[-0.04449797],
[ 0.04216621],
[-0.04717335],
[ 0.23621698],
[ 0.18165808],
[ 0.00605032]])
def equal_weights(returns, rf, params):
a = np.repeat(1/len(returns.columns), len(returns.columns))
return a
equal_weights(utilities_returns, factor_df['RF'], [])
array([0.04545455, 0.04545455, 0.04545455, 0.04545455, 0.04545455,
0.04545455, 0.04545455, 0.04545455, 0.04545455, 0.04545455,
0.04545455, 0.04545455, 0.04545455, 0.04545455, 0.04545455,
0.04545455, 0.04545455, 0.04545455, 0.04545455, 0.04545455,
0.04545455, 0.04545455])
def roll(d, M, T, returns, method, params):
'''
d: number of assets
M: size of window in terms of months
T: total number of periods
returns: T x d dataframe of returns for d assets for T total periods
method: function that computes allocation weights
params: parameters needed for allocation method
'''
X = np.zeros(T-M)
dates = pd.to_datetime(returns.index)
Rf = np.zeros(T-M)
for t in range(M,T):
# get training and testing set
start = dates[t-M]
end = dates[t]
R_train = returns.loc[start:end]
R_test = returns.loc[end]
rf = factor_df['RF'].loc[start:end]
# get allocation weights
a = method(R_train, rf, params)
# get return of next period
X[t-M], Rf[t-M] = a.T @ R_test + (1 - np.sum(a)) * rf[-1], rf[-1]
return X, Rf
def roll_factor(d, M, T, returns, factors, k=0.012):
'''
d: number of assets
M: size of window in terms of months
T: total number of periods
returns: T x d dataframe of returns for d assets for T total periods
factors: factors to be used in factor model
'''
X = np.zeros(T-M)
dates = pd.to_datetime(returns.index)
Rf = np.zeros(T-M)
for t in range(M,T):
# get training and testing set
start = dates[t-M]
end = dates[t]
R_train = returns.loc[start:end]
R_test = returns.loc[end]
rf = factor_df['RF'].loc[start:end]
# get allocation weights
a = factorModel(R_train, factor_df[factors].loc[start:end], rf, kappa=k, numFactors=len(factors))
# get return of next period
X[t-M], Rf[t-M] = a.T @ R_test + (1 - np.sum(a)) * rf[-1], rf[-1]
return X, Rf
d = len(utilities_returns.columns)
M_range = [6, 1*12, 2*12, 5*12] # 1, 2, 5, 8, 10, year windows
T = len(utilities_returns)
k = 0.012
def get_performance_metrics(X, Rf):
risk_premium = X - Rf
ORTN = np.mean(risk_premium)
OSR = np.mean(risk_premium)/np.std(risk_premium)
return [ORTN, OSR] # return, sharpe ratio
def compare_FF_devil(factors, horizon, plot_equal, plot_market, k=0.012):
'''
factors: a list of factors without HML
horizon: investment horizon in terms of years
'''
FF_factors = factors.copy()
FF_factors.append('HML FF')
AF_factors = factors.copy()
AF_factors.append('HML devil')
rf = factor_df['RF'][-1]
for m in M_range:
# factor model
FF, Rf_FF = roll_factor(d, m, T, utilities_returns, FF_factors, k)
AF, Rf_AF = roll_factor(d, m, T, utilities_returns, AF_factors, k)
# stein wolf
SW, Rf_SW = roll(d, m, T, utilities_returns, stein_wolf, [k])
# benchmark 1
equal, Rf_EW = roll(d, m, T, utilities_returns, equal_weights, [])
# benchmark 2
market = np.concatenate((np.repeat(monthly_spy_data['Monthly_Return'].iloc[1],len(FF)-len(monthly_spy_data)+2), monthly_spy_data['Monthly_Return'].iloc[1:-1]))
# rolling of rolling
df = pd.DataFrame({'FF':FF,
'AF':AF,
'SW': SW,
'EW': equal,
'SP':market})
df = df.rolling(horizon * 12).mean()
# performance metrics
PM_FF = get_performance_metrics(FF, Rf_FF)
PM_FF.append(df.mean(axis=0)['FF'])
PM_AF = get_performance_metrics(AF, Rf_AF)
PM_AF.append(df.mean(axis=0)['AF'])
PM_SW = get_performance_metrics(SW, Rf_SW)
PM_SW.append(df.mean(axis=0)['SW'])
PM_EW = get_performance_metrics(equal, Rf_EW)
PM_EW.append(df.mean(axis=0)['EW'])
PM_SP = get_performance_metrics(market, Rf_FF)
PM_SP.append(df.mean(axis=0)['SP'])
df_metrics = pd.DataFrame({'FF': PM_FF,
'AF': PM_AF,
'Stein-Wolf': PM_SW,
'Equal Weights': PM_EW,
'S&P 500': PM_SP},
['ORTN', 'OSR', 'MMAR'])
df_metrics = df_metrics.style.set_caption('Performance Metrics')
display(df_metrics)
# plotting
plt.plot(utilities_returns.index[m:], df['FF'], label='FF ' + str(len(factors)+1) + '-Factor')
plt.plot(utilities_returns.index[m:], df['AF'], label='AF ' + str(len(factors)+1) + '-Factor')
plt.plot(utilities_returns.index[m:], df['SW'], label='Stein-Wolf')
# plt.axhline(y = df.mean(axis=0)['FF'], color = 'blue', alpha=0.66, linestyle = 'dashed')
# plt.axhline(y = df.mean(axis=0)['AF'], color = 'orange', alpha=0.66, linestyle = 'dashed')
# plt.axhline(y = df.mean(axis=0)['SW'], color = 'green', alpha=0.66, linestyle = 'dashed')
if plot_equal:
plt.plot(utilities_returns.index[m:], df['EW'], label='BM: Equal Weights')
#plt.axhline(y = df.mean(axis=0)['Equal Weights'], color = 'purple', alpha=0.66, linestyle = 'dashed')
if plot_market:
plt.plot(utilities_returns.index[m:], df['SP'], label='BM: S&P 500')
#plt.axhline(y = df.mean(axis=0)['S&P 500'], color = 'red', alpha=0.66, linestyle = 'dashed')
plt.suptitle('Avg. Monthly Return Over ' + str(horizon) + '-Year Investment from Utilities Stocks in the S&P 500')
plt.title('Rolling Window of Size ' + str(m) + ' Months')
plt.legend()
plt.ylabel('Return')
plt.xlabel('End of ' + str(horizon) + '-year Investment')
plt.show()
# 3 factor with BM
compare_FF_devil(['MKT','SMB'], 10, 1, 1, 0.0117)
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009030 | 0.009216 | 0.009181 | 0.007889 | 0.007991 |
| OSR | 1.264365 | 1.353326 | 2.267006 | 0.184906 | 0.206700 |
| MMAR | 0.011609 | 0.011809 | 0.011758 | 0.009764 | 0.009657 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009438 | 0.009414 | 0.009680 | 0.007633 | 0.007968 |
| OSR | 0.757602 | 0.748519 | 1.499537 | 0.178207 | 0.204765 |
| MMAR | 0.011847 | 0.011842 | 0.012029 | 0.009719 | 0.009552 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.008275 | 0.008158 | 0.018793 | 0.007429 | 0.007874 |
| OSR | 0.395090 | 0.397392 | 0.456066 | 0.173243 | 0.199688 |
| MMAR | 0.010323 | 0.010270 | 0.022434 | 0.009647 | 0.009326 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009186 | 0.009351 | 0.019122 | 0.007597 | 0.007446 |
| OSR | 0.257708 | 0.262761 | 0.517912 | 0.178725 | 0.181125 |
| MMAR | 0.011867 | 0.011954 | 0.021978 | 0.009532 | 0.008438 |
# 3 factor w/o BM
compare_FF_devil(['MKT','SMB'], 10, 0, 0, 0.0117)
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009030 | 0.009216 | 0.009181 | 0.007889 | 0.007991 |
| OSR | 1.264366 | 1.353325 | 2.267005 | 0.184906 | 0.206700 |
| MMAR | 0.011609 | 0.011809 | 0.011758 | 0.009764 | 0.009657 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009438 | 0.009414 | 0.009680 | 0.007633 | 0.007968 |
| OSR | 0.757602 | 0.748519 | 1.499537 | 0.178207 | 0.204765 |
| MMAR | 0.011847 | 0.011842 | 0.012029 | 0.009719 | 0.009552 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.008275 | 0.008158 | 0.018793 | 0.007429 | 0.007874 |
| OSR | 0.395090 | 0.397392 | 0.456096 | 0.173243 | 0.199688 |
| MMAR | 0.010323 | 0.010270 | 0.022434 | 0.009647 | 0.009326 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009186 | 0.009351 | 0.019122 | 0.007597 | 0.007446 |
| OSR | 0.257708 | 0.262761 | 0.517912 | 0.178725 | 0.181125 |
| MMAR | 0.011867 | 0.011954 | 0.021978 | 0.009532 | 0.008438 |
# ff 5-factor with BM
compare_FF_devil(['MKT','SMB','RMW','CMA'], 10, 1, 1, 0.0117)
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009127 | 0.009171 | 0.009181 | 0.007889 | 0.007991 |
| OSR | 1.712918 | 1.829175 | 2.267005 | 0.184906 | 0.206700 |
| MMAR | 0.011620 | 0.011723 | 0.011758 | 0.009764 | 0.009657 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009390 | 0.009420 | 0.009680 | 0.007633 | 0.007968 |
| OSR | 0.887208 | 0.880773 | 1.499537 | 0.178207 | 0.204765 |
| MMAR | 0.011677 | 0.011659 | 0.012029 | 0.009719 | 0.009552 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.008368 | 0.008345 | 0.018793 | 0.007429 | 0.007874 |
| OSR | 0.450301 | 0.450284 | 0.456096 | 0.173243 | 0.199688 |
| MMAR | 0.010377 | 0.010388 | 0.022434 | 0.009647 | 0.009326 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009437 | 0.009499 | 0.019122 | 0.007597 | 0.007446 |
| OSR | 0.275000 | 0.278442 | 0.517912 | 0.178725 | 0.181125 |
| MMAR | 0.012036 | 0.012014 | 0.021978 | 0.009532 | 0.008438 |
# ff 5-factor w/o BM
compare_FF_devil(['MKT','SMB','RMW','CMA'], 10, 0, 0, 0.0117)
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009127 | 0.009171 | 0.009181 | 0.007889 | 0.007991 |
| OSR | 1.712918 | 1.829175 | 2.267005 | 0.184906 | 0.206700 |
| MMAR | 0.011620 | 0.011723 | 0.011758 | 0.009764 | 0.009657 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009390 | 0.009420 | 0.009680 | 0.007633 | 0.007968 |
| OSR | 0.887208 | 0.880773 | 1.499537 | 0.178207 | 0.204765 |
| MMAR | 0.011677 | 0.011659 | 0.012029 | 0.009719 | 0.009552 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.008368 | 0.008345 | 0.018793 | 0.007429 | 0.007874 |
| OSR | 0.450301 | 0.450284 | 0.456096 | 0.173243 | 0.199688 |
| MMAR | 0.010377 | 0.010388 | 0.022434 | 0.009647 | 0.009326 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009437 | 0.009499 | 0.019122 | 0.007597 | 0.007446 |
| OSR | 0.275000 | 0.278442 | 0.517912 | 0.178725 | 0.181125 |
| MMAR | 0.012036 | 0.012014 | 0.021978 | 0.009532 | 0.008438 |
# aqr 5-factor with BM
compare_FF_devil(['MKT','SMB','MOM','STR'], 10, 1, 1, 0.0117)
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009258 | 0.009124 | 0.009181 | 0.007889 | 0.007991 |
| OSR | 1.976301 | 1.987609 | 2.267005 | 0.184906 | 0.206700 |
| MMAR | 0.011977 | 0.011790 | 0.011758 | 0.009764 | 0.009657 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009616 | 0.009684 | 0.009680 | 0.007633 | 0.007968 |
| OSR | 0.910463 | 0.906989 | 1.499537 | 0.178207 | 0.204765 |
| MMAR | 0.012024 | 0.012043 | 0.012029 | 0.009719 | 0.009552 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.008645 | 0.008522 | 0.018793 | 0.007429 | 0.007874 |
| OSR | 0.461676 | 0.455831 | 0.456096 | 0.173243 | 0.199688 |
| MMAR | 0.010604 | 0.010541 | 0.022434 | 0.009647 | 0.009326 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009690 | 0.009711 | 0.019122 | 0.007597 | 0.007446 |
| OSR | 0.288782 | 0.288543 | 0.517912 | 0.178725 | 0.181125 |
| MMAR | 0.012213 | 0.012223 | 0.021978 | 0.009532 | 0.008438 |
# aqr 5-factor w/o BM
compare_FF_devil(['MKT','SMB','MOM','STR'], 10, 0, 0, 0.0117)
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009258 | 0.009124 | 0.009181 | 0.007889 | 0.007991 |
| OSR | 1.976301 | 1.987609 | 2.267005 | 0.184906 | 0.206700 |
| MMAR | 0.011977 | 0.011790 | 0.011758 | 0.009764 | 0.009657 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009616 | 0.009684 | 0.009680 | 0.007633 | 0.007968 |
| OSR | 0.910463 | 0.906989 | 1.499537 | 0.178207 | 0.204765 |
| MMAR | 0.012024 | 0.012043 | 0.012029 | 0.009719 | 0.009552 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.008645 | 0.008522 | 0.018793 | 0.007429 | 0.007874 |
| OSR | 0.461676 | 0.455831 | 0.456096 | 0.173243 | 0.199688 |
| MMAR | 0.010604 | 0.010541 | 0.022434 | 0.009647 | 0.009326 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009690 | 0.009711 | 0.019122 | 0.007597 | 0.007446 |
| OSR | 0.288782 | 0.288543 | 0.517912 | 0.178725 | 0.181125 |
| MMAR | 0.012213 | 0.012223 | 0.021978 | 0.009532 | 0.008438 |
# 6-factor with BM
compare_FF_devil(['MKT','SMB','RMW','CMA','MOM'], 10, 1, 1, 0.0117)
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | nan | nan | 0.009181 | 0.007889 | 0.007991 |
| OSR | nan | nan | 2.267005 | 0.184906 | 0.206700 |
| MMAR | nan | nan | 0.011758 | 0.009764 | 0.009657 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009431 | 0.009418 | 0.009680 | 0.007633 | 0.007968 |
| OSR | 0.928292 | 0.929859 | 1.499537 | 0.178207 | 0.204765 |
| MMAR | 0.011719 | 0.011681 | 0.012029 | 0.009719 | 0.009552 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.008754 | 0.008618 | 0.018793 | 0.007429 | 0.007874 |
| OSR | 0.496899 | 0.486006 | 0.456096 | 0.173243 | 0.199688 |
| MMAR | 0.010715 | 0.010679 | 0.022434 | 0.009647 | 0.009326 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009793 | 0.009791 | 0.019122 | 0.007597 | 0.007446 |
| OSR | 0.294743 | 0.296314 | 0.517912 | 0.178725 | 0.181125 |
| MMAR | 0.012271 | 0.012263 | 0.021978 | 0.009532 | 0.008438 |
# 6-factor w/o BM
compare_FF_devil(['MKT','SMB','RMW','CMA','MOM'], 10, 0, 0, 0.0117)
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | nan | nan | 0.009181 | 0.007889 | 0.007991 |
| OSR | nan | nan | 2.267005 | 0.184906 | 0.206700 |
| MMAR | nan | nan | 0.011758 | 0.009764 | 0.009657 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009431 | 0.009418 | 0.009680 | 0.007633 | 0.007968 |
| OSR | 0.928292 | 0.929859 | 1.499537 | 0.178207 | 0.204765 |
| MMAR | 0.011719 | 0.011681 | 0.012029 | 0.009719 | 0.009552 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.008754 | 0.008618 | 0.018793 | 0.007429 | 0.007874 |
| OSR | 0.496899 | 0.486006 | 0.456096 | 0.173243 | 0.199688 |
| MMAR | 0.010715 | 0.010679 | 0.022434 | 0.009647 | 0.009326 |
| FF | AF | Stein-Wolf | Equal Weights | S&P 500 | |
|---|---|---|---|---|---|
| ORTN | 0.009793 | 0.009791 | 0.019122 | 0.007597 | 0.007446 |
| OSR | 0.294743 | 0.296314 | 0.517912 | 0.178725 | 0.181125 |
| MMAR | 0.012271 | 0.012263 | 0.021978 | 0.009532 | 0.008438 |
factorModel